package kik.client;

import java.util.ArrayList;

import kik.client.chat.Chat;
import kik.client.chat.ChatChange;
import kik.client.common.Change;
import kik.client.whiteboard.Whiteboard;
import kik.client.whiteboard.WhiteboardChange;

import com.calclab.suco.client.events.Listener;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;

public class Conference extends Composite implements Listener<Change> {
	private String conferenceId;
	private ConferenceManager confMan;
	private ArrayList<String> members = new ArrayList<String>();
	private ArrayList<String> invited = new ArrayList<String>();
	private Chat chat = new Chat(this);
	private Whiteboard whiteboard = new Whiteboard(this);
	private HorizontalPanel mainPanel = new HorizontalPanel();
	private Button close = new Button();

	/**
	 * Konstruktor nowej konferencji.
	 * @param id identyfikator konferencji
	 * @param _confMan referencja do zarządcy konferencji.
	 */
	public Conference(String id, ConferenceManager _confMan) {
		whiteboard.addStyleName("whiteboard");
		chat.setStyleName("chat");
		close.setText("X");
		close.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				if(Window.confirm("Close this conference?"))
					exitConference();
			}
		});
		conferenceId = id;
		confMan = _confMan;
		chat.setOwner(confMan.getLogin());
		whiteboard.setOwner(confMan.getLogin());
		//DecoratorPanel pretty1 = new DecoratorPanel();
		//pretty1.add(whiteboard);
		//DecoratorPanel pretty2 = new DecoratorPanel();
		//pretty2.add(chat);

		//mainPanel.setSpacing(8);
		//mainPanel.add(pretty1);
		//mainPanel.add(pretty2);
		mainPanel.add(whiteboard);
		mainPanel.add(chat);
		mainPanel.add(close);
		
		initWidget(mainPanel);
	}

	/**
	 * Funkcja zamykająca konferencję
	 * @see ConferenceManager#exitConference(Conference)
	 */
	
	public void exitConference(){
		confMan.exitConference(this);
	}

	/**
	 * Funkcja dodająca nowego uczestnika do konferencji.
	 * @param newMember jabberId nowego uczestnika konferencji
	 */
	
	public void addMember(String newMember) {
		for(int i = 0; i < members.size(); ++i) {
			if(members.get(i).compareTo(newMember)==0) {
				return;
			}
		}
		//sa dwie mozliwosci:
		//1. uzytkownik zaakceptowal konferencje (gdy jest w invMembers, wiec trzeba wszystkich
		// innych poinformowac, ze jest nowy czlonek
		if(invited.contains(newMember)){
			confMan.sendTo(members, new MemberChange(newMember, "joined", conferenceId));
			chat.syncWith(newMember);
			whiteboard.syncWith(newMember);
			removeInvMember(newMember); //trzeba usunac z zaproszonych
		}
		//2. inny uzytkownik zaprosil kogos i przyslal info,
		members.add(newMember);
		chat.refreshContacts();
	}
	
	/**
	 * Funkcja zapraszająca nowego użytkownika do konferencji.
	 * @param newMember JabberId zaproszonego uczestnika.
	 */
	
	public void inviteMember(String newMember) {
		for(int i = 0; i < invited.size(); ++i) {
			if(invited.get(i).compareTo(newMember) == 0) {
				return;
			}
		}
		for(int i = 0; i < members.size(); ++i) {
			if(members.get(i).compareTo(newMember) == 0) {
				return;
			}
		}
		invited.add(newMember);
		
		//wysylamy zaproszenie i czekamy na odpowiedz
		confMan.sendTo(newMember, new NewConference(members, confMan.getLogin(), conferenceId));
	}
	
	/**
	 * Funkcja usuwająca uczestnika z konferencji.
	 * @param member JabberId uczestnika usuwanego z konferencji. 
	 */
	
	public void removeMember(String member) {
		for(int i = 0; i < members.size(); ++i) {
			if(members.get(i).compareTo(member) == 0) {
				members.remove(i);
				chat.refreshContacts();
				return;
			}
		}
	}

	/**
	 * Funkcja usuwająca użytkownika z listy zaproszonych użytkowników.
	 * @param member JabberId użytkownika usuwanego z listy zaproszonych użytkowników.
	 */
	
	public void removeInvMember(String member) {
		for(int i = 0; i < invited.size(); ++i) {
			if(invited.get(i).compareTo(member) == 0) {
				invited.remove(i);
				return;
			}
		}
	}
	
	/**
	 * Funkcja ustawiająca listę członków konferencji.
	 * @param members nowa lista członków konferencji.
	 */
	
	public void setMembers(ArrayList<String> members) {
		this.members = members;
		chat.refreshContacts();
	}

	/**
	 * Funkcja zwracająca aktualną listę uczestników konferencji.
	 * @return aktualna lista uczestników konferencji.
	 */
	
	public ArrayList<String> getMembers() {
		return members;
	}
	
	/**
	 * Funkcja zwracająca identyfikator konferencji.
	 * @return identyfikator konferencji.
	 */
	
	public String getConferenceId() {
		return this.conferenceId;
	}


	/**
	 * Funkcja obsługująca zmianę w konferencji.
	 * @param change zmiana w konferencji.
	 */
	
	public void onEvent(Change change) {
		// odebrano obiekt zmian, trzeba sprawdzi�, czy do nas adresowany
		GWT.log(conferenceId +":"+change.getFromID(), null);
		if(change.getFromID() == null || conferenceId.compareTo(change.getFromID()) == 0){
			//do nas adresowana jest przesy�ka. Nale�y zrobi� co� z danymi.
			//TODO
			GWT.log("Odebrano obiekt zmian! Od: " + change.getFromUser() 
					+ "; Id konf z przesy�ki: "+ change.getFromID(), null);
			GWT.log("Odebrano obiekt: '"+change.getType()+"'", null);
			
			if(change.getType().compareTo("ChatChange") == 0){
				chat.handleChatChange((ChatChange) change);
			}
			if(change.getType().compareTo("WhiteboardChange") == 0){
				whiteboard.handlewhiteboardChange((WhiteboardChange) change);
			}
			if(change.getType().compareTo("MemberChange") == 0){
				MemberChange mc = (MemberChange) change;
				
				//uzytkownik dolaczyl do konferencji
				if(mc.getAction().compareTo("joined") == 0){
					addMember(mc.getMember());
					chat.refreshContacts();
				}
				else if(mc.getAction().compareTo("exited") == 0){
					removeInvMember(mc.getMember());
					removeMember(mc.getMember());
				}
			}
		}
		
	}
	
	/**
	 * Funkcja wysyłająca obiekt zmiany do pozostałych uczestników konferencji.
	 * @param change obiekt zmiany.
	 */
	
	public void send(Change change) {
		// wysyłanie obiektu zmian do wszystkich z konferencji
		//GWT.log(members.toString(), null);
		confMan.sendTo(members, change);
	}
	/**
	 * Funkcja wysyłająca obiekt zmiany do konkretnego uczestnika konferencji.
	 * @param member	Uczestnik konferecji do którego ma zostać przesłana wiadomość.
	 * @param change	Obiekt zmiany.
	 */
	public void sendTo(String member, Change change) {
		confMan.sendTo(member, change);
	}
}